import pyautogui
import time,random
import cv2
import numpy as np


def auto_walk(x,y):
    # 随机乱走
    random_x = [(i-3)*21+x for i in range(7)]
    random_y = [(i-3)*21+y for i in range(9)]
    while 1:
        pyautogui.moveTo(random.choice(random_x), random.choice(random_y), 0.1)
        pyautogui.click()
        time.sleep(2)

class ListNode:
    def __init__(self,head_pos,now_pos,value=1):
        # 每个新节点初始化
        self.head_pos = head_pos
        self.now_pos = now_pos
        # self.value = value  # 1:路，0:墙或其他，不用回溯应该用得着这个值
        self.next_node = [(0,-1),(-1,0),(0,1),(1,0)]    # 单位向量
        # 删掉指向头节点的向量
        side = (head_pos[0]-now_pos[0],head_pos[1]-now_pos[1])
        if side in self.next_node:
            self.next_node.remove(side)

def judge_pic(mid_pos):
    # 对比相似度
    img = myscreenshot(mid_pos)
    res = model_compare(mid_pos,img)
    if res>0.9:
        return False
    else:
        return True

def myscreenshot(mid_pos,cut_area=None):
    # 截屏区域
    x,y = mid_pos
    if cut_area=='f':
        # 截楼层
        img = pyautogui.screenshot(region=[x+50*2,y-50*6.5,50*1.6,50*0.5])
    elif cut_area=='b':
        # 截开宝箱后的区域
        img = pyautogui.screenshot(region=[x-50*3.06,y-50*5.24,50*0.3,50*0.3])
    else:
        img = pyautogui.screenshot(region=[x-50*3.5,y-50*4.5,7*50,9*50])
    img = cv2.cvtColor(np.array(img),cv2.COLOR_RGB2BGR)
    return img

def model_compare(mid_pos,img,name='ss'):
    # 直接模板匹配简单粗暴
    try:
        img0 = cv2.imread(r'./%s.jpg'%name)
    except Exception as e:
        print('####################',e)
        cv2.imwrite('./%s.jpg'%name,img)
        return 0
    # 模板匹配，不动时相似度大约>0.9，任意移动一格相似度降到0.5、0.6附近
    result = cv2.matchTemplate(img0, img, cv2.TM_CCOEFF_NORMED)
    if result[0][0]<0.9:
        # 本来想对开宝箱的动画做个识别，没有合适的固定区域作罢
        # time.sleep(.3)
        # img_box = cv2.imread(r'./box.jpg')
        # img_box_new = myscreenshot(mid_pos,'b')
        # result2 = cv2.matchTemplate(img_box, img_box_new, cv2.TM_CCOEFF_NORMED)
        # print('???',result2[0][0])
        # if result2[0][0]>0.99:
        #     print(result2[0][0],'开宝箱/材料')
        #     return 1
        cv2.imwrite('./%s.jpg' % name, img)
    return result[0][0]

class BackTrackWalk:
    def __init__(self,start_node):
        self.track = [start_node]

    def auto_move(self,mid_pos,side):
        # side: 单位向量
        pyautogui.moveTo(mid_pos[0]+side[0]*50, mid_pos[1]+side[1]*50, 0.1)
        pyautogui.click()
        time.sleep(.2)

    def backtrack_walk(self,node,mid_pos):
        # 每次回溯时要截图，避免bug
        # 重复性检测
        been_road = [i.now_pos for i in self.track[:-1]]
        if len(self.track)>1 and node.now_pos in been_road:
            print(been_road,node.now_pos)
            side = (node.head_pos[0]-node.now_pos[0],node.head_pos[1]-node.now_pos[1])
            self.auto_move(mid_pos,side)
            self.track.pop()
            self.track[-1].next_node.pop(0)
            print('路径重复回溯',self.track[-1].now_pos,self.track[-1].next_node)
            return
        while len(node.next_node)>0:
            # 移动
            self.auto_move(mid_pos,node.next_node[0])
            time.sleep(4)   # 这个sleep是对所有开宝箱、捡东西、楼层变化的过场动画的简单处理，sleep完尘归尘、土归土，不会再导致误识别，但作为脚本耗时太久了
            res = judge_pic(mid_pos)
            if res:
                # 实例化新节点
                next_pos = (node.now_pos[0] + node.next_node[0][0], node.now_pos[1] + node.next_node[0][1])
                next_n = ListNode(node.now_pos,next_pos)
                self.track.append(next_n)
                print('到达新节点',next_n.now_pos,next_n.next_node)
                return True
            else:
                del_node = node.next_node.pop(0)
                print('下一节点不通',node.now_pos,node.next_node,del_node)
        if not node.next_node:  # 死胡同，走回头路，并从栈顶弹出此节点
            if node.head_pos == (0,0):
                return
            side = (node.head_pos[0]-node.now_pos[0],node.head_pos[1]-node.now_pos[1])
            self.auto_move(mid_pos,side)
            self.track.pop()
            self.track[-1].next_node.pop(0)
            print('死胡同回溯',self.track[-1].now_pos,self.track[-1].next_node)


if __name__ == '__main__':
    middle = (1601,565)
    img1 = myscreenshot(middle)
    cv2.imwrite('./ss.jpg', img1)
    img2 = myscreenshot(middle, 'f')
    cv2.imwrite('./floor.jpg', img2)
    btw = BackTrackWalk(ListNode((0,0),(0,0)))
    while len(btw.track)>1 or (len(btw.track)==1 and len(btw.track[0].next_node)>0):
        if btw.track[-1].now_pos==(0,-1):
            print(len(btw.track),btw.track[0].next_node)
        walk_res = btw.backtrack_walk(btw.track[-1],middle)
        if not walk_res:
            time.sleep(2)
        else:
            img = myscreenshot(middle,'f')
            score = model_compare(middle,img,'floor')
            if score<0.98:   # 进下一层重置track
                print('进入下一层')
                btw.track = [ListNode((0,0),(0,0))]
                cv2.imwrite('./floor.jpg', img)
        img = myscreenshot(middle)
        cv2.imwrite('./ss.jpg', img)
    for i in btw.track:
        print(i.head_pos,i.next_node)